/**
 * Copyright (C) 2010 Sergey Grigoriev <s.a.grigoriev@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.gmf.mojos

import com.google.inject.Inject
import com.google.inject.Injector
import javax.script.ScriptEngine
import javax.script.ScriptEngineManager
import net.gmf.dsl.FlexProject
import org.apache.commons.io.FilenameUtils
import org.apache.log4j.Logger
import org.apache.maven.artifact.handler.ArtifactHandler
import org.apache.maven.artifact.repository.ArtifactRepository
import org.apache.maven.artifact.resolver.ArtifactResolver
import org.apache.maven.project.MavenProject
import org.codehaus.groovy.maven.mojo.GroovyMojo
import net.gmf.core.FlexSdkFacade
import net.gmf.core.ProjectContext
import net.gmf.core.Bootstrapper
import net.gmf.core.ProjectScopeModule

/**
 * @requiresDependencyResolution true
 */
abstract class GMavenMojo extends GroovyMojo {

  /**
   * Maven Project instance.
   *
   * @parameter default-value="${project}"
   * @required
   * @readonly
   */
  MavenProject project

  /**
   * Local repository required to resolve dependencies.
   *
   * @parameter expression="${localRepository}"
   */
  protected ArtifactRepository localRepository;

  /**
   * List of remote repositories required to resolve dependencies.
   *
   * @parameter expression="${project.remoteArtifactRepositories}"
   */
  protected List remoteRepositories;

  /**
   * @component
   */
  protected ArtifactResolver resolver

  /**
   * @component role-hint='swf'
   */
  protected ArtifactHandler swfArtifactHandler

  /**
   * @component role-hint='swc'
   */
  protected ArtifactHandler swcArtifactHandler

  protected final Logger l4j = Logger.getLogger(getClass())

  @Inject
  protected FlexSdkFacade flexSdkFacade


  @Inject
  protected FlexProject builder

  @Inject
  protected ProjectContext ctx

  /**
   * @component
   */
  private Bootstrapper bootstrapper

  private void initialize() {
    bootstrapper.initialize(swfArtifactHandler, swcArtifactHandler, resolver, localRepository, remoteRepositories)
    if (project.gmfInjector) {
      if (!flexSdkFacade) project.gmfInjector.injectMembers(this)
      return
    }
    fromParentsToChild { MavenProject prj -> createInjector(prj)}
    project.gmfInjector.injectMembers(this)
    fromParentsToChild { MavenProject prj -> readConfigurationScript(prj) }
    
    flexSdkFacade.flexSdkHome = builder.rootNode.flexSdkHome
  }

  protected final void createInjector(MavenProject prj) {
    Injector injector = prj.gmfInjector
    if (!injector) {
      ProjectScopeModule module = new ProjectScopeModule(prj)
      injector = bootstrapper.injector.createChildInjector(module)
      prj.gmfInjector = injector
    }
  }


  void execute() {
    initialize()
    createCommand()?.run()
  }

  protected final void fromParentsToChild(closure) {
    def projectsChain = []
    for (MavenProject currentProject = project; currentProject != null && currentProject.basedir != null; currentProject = currentProject.parent) {
      projectsChain << currentProject;
    }
    projectsChain.reverse().each { MavenProject prj ->
      closure(prj)
    }
  }

  protected final void readConfigurationScript(MavenProject prj) {

    Injector injector = prj.gmfInjector
    ProjectContext ctx = (ProjectContext) injector.getInstance(ProjectContext)
    builder.ctx = ctx

    ScriptEngineManager factory = new ScriptEngineManager();
    ScriptEngine engine = factory.getEngineByName("Groovy");

    def writer = new StringWriter()
    engine.getContext().setWriter(writer)

    def buildScript = FilenameUtils.concat(prj.basedir.path, "build-flex.groovy")
    if (!new File(buildScript).exists()) {
      return;
    }

    Reader reader = new FileReader(buildScript)

    def bindings = engine.createBindings()

    bindings.put('build', { builder.build(it) })

    try {
      engine.eval(reader, bindings)
    }

    finally {
      if (writer.toString()) {
        l4j.info(writer.toString())
      }
    }
  }

  /**
   * Creates a command to execute
   * @return a command with 'run' method or null
   */
  def protected createCommand() {}
}
